Skip to content

Add MDS035 rule to flag renderer-specific TOC directives - #144

Merged
jeduden merged 2 commits into
mainfrom
claude/plan-88-toc-directive
Apr 19, 2026
Merged

Add MDS035 rule to flag renderer-specific TOC directives#144
jeduden merged 2 commits into
mainfrom
claude/plan-88-toc-directive

Conversation

@jeduden

@jeduden jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner

Summary

Implements MDS035 (toc-directive), a new opt-in linting rule that detects renderer-specific table-of-contents directives that render as literal text in CommonMark and goldmark.

Key Changes

  • New rule implementation (internal/rules/tocdirective/rule.go):

    • Detects four TOC directive variants: [TOC], [[_TOC_]], [[toc]], and ${toc}
    • Scans paragraphs line-by-line using regex patterns to identify directives on their own line
    • Suppresses [TOC] diagnostics when a matching link reference definition exists (case-insensitive per CommonMark)
    • Properly ignores directives inside code blocks and inline code spans via AST walking
    • Registered as MDS035 in the meta category, disabled by default (opt-in)
  • Comprehensive test suite (internal/rules/tocdirective/rule_test.go):

    • Tests all four directive variants
    • Validates suppression of directives in code blocks (fenced and indented)
    • Validates suppression of directives in inline code spans
    • Tests link reference definition matching (case-insensitive)
    • Confirms rule is detection-only (no auto-fix)
  • Documentation and fixtures:

    • Rule documentation in internal/rules/MDS035-toc-directive/README.md with rationale for detection-only approach
    • Good fixture showing directives in code blocks and inline code (no diagnostics)
    • Good fixture demonstrating [TOC] as legitimate link via reference definition
    • Bad fixtures for each of the four directive variants
  • Integration updates:

    • Registered rule in test imports and main command
    • Updated plan status to complete
    • Added renderer portability section to docs/background/markdown-linters.md
    • Updated rule index documentation

Implementation Details

The rule uses goldmark's parser context to check for link reference definitions, delegating label normalization and code-block scoping to the parser rather than approximating them at the source level. This ensures accurate handling of CommonMark's case-insensitive label matching and proper exclusion of definitions inside code blocks.

The diagnostic message guides users toward two alternatives: <?catalog?> for file-index use cases (MDS019) or manual maintenance for in-document heading TOCs.

https://claude.ai/code/session_01T569bC9ogHHf5A6Cgxn9NW

@codecov

codecov Bot commented Apr 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.82540% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.76%. Comparing base (fef3ac3) to head (5e7c283).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
internal/rules/tocdirective/rule.go 96.55% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #144      +/-   ##
==========================================
+ Coverage   86.70%   86.76%   +0.05%     
==========================================
  Files          95       96       +1     
  Lines       10387    10446      +59     
==========================================
+ Hits         9006     9063      +57     
- Misses        899      900       +1     
- Partials      482      483       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a new opt-in linting rule (MDS035: toc-directive) to detect renderer-specific TOC tokens that render as literal text under CommonMark/goldmark.

Changes:

  • Added MDS035 rule implementation and unit tests to detect [TOC], [[_TOC_]], [[toc]], and ${toc}, with [TOC] suppressed when a matching link reference definition exists.
  • Added fixtures and documentation for MDS035 and updated rule indexes/background docs.
  • Registered the new rule in the CLI and test import sets; updated integration fixture settings restoration behavior.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
plan/88_toc-directive-migration.md Marks the TOC-directive migration plan as completed.
internal/rules/tocdirective/rule.go Adds the MDS035 rule implementation.
internal/rules/tocdirective/rule_test.go Adds unit tests for directive detection/suppression behavior.
internal/rules/index.md Adds MDS035 to the rules index table.
internal/rules/MDS035-toc-directive/README.md Documents the new rule, configuration, and examples.
internal/rules/MDS035-toc-directive/good/*.md Adds “good” fixtures for non-diagnostics cases (code, link-ref suppression).
internal/rules/MDS035-toc-directive/bad/*.md Adds “bad” fixtures for each directive variant.
internal/integration/rules_test.go Changes fixture settings application to snapshot/restore rule state.
internal/engine/categories_test.go Imports the new rule for category-related tests.
internal/config/config_test.go Imports the new rule for config-related tests.
docs/background/markdown-linters.md Adds a renderer portability section referencing MDS035.
cmd/mdsmith/main.go Registers the new rule in the main binary imports.
PLAN.md Updates plan catalog status for item 88.

Comment thread internal/rules/tocdirective/rule.go Outdated
jeduden pushed a commit that referenced this pull request Apr 19, 2026
hasTOCLinkReference previously used goldmark.New(), which omits
mdsmith's PIBlockParserPrioritized. Extract the parser construction in
lint.NewFile into an exported lint.NewParser() so rules that need a
secondary parse (here, to consult the link reference map for [TOC]
suppression) stay consistent with the original lint parse instead of
drifting from it. No behavior change on the current test corpus;
defensive alignment for future parser additions.

Addresses review feedback on PR #144.
@jeduden
jeduden requested a review from Copilot April 19, 2026 19:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

@jeduden jeduden added queue Add to a PR to enqueue it queue:active Applied automatically when a PR is in an active batch and removed queue Add to a PR to enqueue it labels Apr 19, 2026
@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

🟢 Merge Queue — picked up

This PR is in the queue and will be batched with other queue-labelled PRs.

Next: No action needed — you'll get another comment when CI starts on the batch. View merge queue run.

@jeduden jeduden added queue:failed Applied automatically when CI fails or merge conflict occurs and removed queue:active Applied automatically when a PR is in an active batch labels Apr 19, 2026
@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

⚠️ Merge Queue — merge conflict

This PR could not be merged into the batch branch without conflicts with main or another queued PR.

Next: Rebase onto or merge main into your branch, resolve conflicts, push, then re-add the queue label.

jeduden pushed a commit that referenced this pull request Apr 19, 2026
hasTOCLinkReference previously used goldmark.New(), which omits
mdsmith's PIBlockParserPrioritized. Extract the parser construction in
lint.NewFile into an exported lint.NewParser() so rules that need a
secondary parse (here, to consult the link reference map for [TOC]
suppression) stay consistent with the original lint parse instead of
drifting from it. No behavior change on the current test corpus;
defensive alignment for future parser additions.

Addresses review feedback on PR #144.
@jeduden
jeduden force-pushed the claude/plan-88-toc-directive branch from 2fb0f4c to cdb2caf Compare April 19, 2026 20:52
@jeduden jeduden added queue Add to a PR to enqueue it queue:active Applied automatically when a PR is in an active batch and removed queue:failed Applied automatically when CI fails or merge conflict occurs queue Add to a PR to enqueue it labels Apr 19, 2026
@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

🟢 Merge Queue — picked up

This PR is in the queue and will be batched with other queue-labelled PRs.

Next: No action needed — you'll get another comment when CI starts on the batch. View merge queue run.

@jeduden jeduden removed the queue:active Applied automatically when a PR is in an active batch label Apr 19, 2026
@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

⚠️ Merge Queue — merge conflict

This PR could not be merged into the batch branch without conflicts with main or another queued PR.

Next: Rebase onto or merge main into your branch, resolve conflicts, push, then re-add the queue label.

@jeduden jeduden added the queue:failed Applied automatically when CI fails or merge conflict occurs label Apr 19, 2026
claude added 2 commits April 19, 2026 20:54
Add a new opt-in rule that flags renderer-specific table-of-contents
directives which render as literal text on CommonMark and goldmark:

- `[TOC]` (Python-Markdown / MultiMarkdown / Pandoc)
- `[[_TOC_]]` (GitLab, Azure DevOps)
- `[[toc]]` (markdown-it, VitePress)
- `${toc}` (VitePress configs)

Detection is paragraph-scoped line matching, so fenced/indented code
blocks and inline code spans are naturally excluded. For the `[TOC]`
variant only, a matching link reference definition suppresses the
diagnostic, because the token then resolves to a legitimate link.

Side fix: integration test cleanup now snapshots the rule's value via
reflect and restores it on cleanup, rather than calling
`ApplySettings(DefaultSettings())`. The previous approach left
directory-structure's `configured` flag set across tests, which only
surfaced as a warning now that MDS035 is the first fixture to run
after MDS033 and triggered the `sync.Once` warning.

https://claude.ai/code/session_$(uuidgen 2>/dev/null | tr -d - | head -c 22 || echo 01T569bC9ogHHf5A6Cgxn9NW)
hasTOCLinkReference previously used goldmark.New(), which omits
mdsmith's PIBlockParserPrioritized. Extract the parser construction in
lint.NewFile into an exported lint.NewParser() so rules that need a
secondary parse (here, to consult the link reference map for [TOC]
suppression) stay consistent with the original lint parse instead of
drifting from it. No behavior change on the current test corpus;
defensive alignment for future parser additions.

Addresses review feedback on PR #144.
@jeduden jeduden added the queue Add to a PR to enqueue it label Apr 19, 2026
@jeduden
jeduden force-pushed the claude/plan-88-toc-directive branch from cdb2caf to 5e7c283 Compare April 19, 2026 20:54
@jeduden jeduden removed the queue:failed Applied automatically when CI fails or merge conflict occurs label Apr 19, 2026
Copilot AI review requested due to automatic review settings April 19, 2026 20:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

@jeduden jeduden added queue Add to a PR to enqueue it queue:active Applied automatically when a PR is in an active batch and removed queue Add to a PR to enqueue it labels Apr 19, 2026
@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

🟢 Merge Queue — picked up

This PR is in the queue and will be batched with other queue-labelled PRs.

Next: No action needed — you'll get another comment when CI starts on the batch. View merge queue run.

@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

🔵 Merge Queue — CI running

Merged into batch branch merge-queue/batch-144-1776633485. View CI run.

Next: No action needed — you'll be notified when CI completes.

@jeduden jeduden removed the queue:active Applied automatically when a PR is in an active batch label Apr 19, 2026
@jeduden

jeduden commented Apr 19, 2026

Copy link
Copy Markdown
Owner Author

Merge Queue — merged

This PR landed on main via commit 7958dcd. CI run that validated the merge.

Next: Done — nothing more to do here.

@jeduden
jeduden merged commit 7958dcd into main Apr 19, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants